<html>
<head>
  <meta http-equiv="refresh" content="600">
</head>
<body>
<table>
<tr>
<td align="center">
Explorer
</td>
</tr>
<tr>
<td>
<canvas id="the_canvas" width=900 height=600></canvas>
<audio id="add_block_sound" src="http://rpg.hamsterrepublic.com/wiki-images/0/04/TextboxBloop8-Bit.ogg" preload="auto" autobuffer></audio>
<audio id="remove_block_sound" src="http://rpg.hamsterrepublic.com/wiki-images/3/3a/Thip.ogg" preload="auto" autobuffer></audio>
</td>
</tr>
<tr>
</tr>
</table>
<script type="text/javascript">

var position = [0, 0];
var canvas = document.getElementById("the_canvas");
var context = canvas.getContext("2d");
var num_blocks = 50;
var block_size = 20;
var blocks = new Array(num_blocks);
var assets = {};

function InitializeWorld() {
  var guy = new Image();
  guy.src = "stick_guy.png";
  assets["guy"] = guy;

  var block = new Image();
  block.src = "blocks/earth_block.png";
  assets["blocks/earth"] = block;

  block = new Image();
  block.src = "blocks/top_block.png";
  assets["blocks/top"] = block;

  block = new Image();
  block.src = "blocks/sky.png";
  assets["blocks/sky"] = block;

  block = new Image();
  block.src = "blocks/wood.png";
  assets["blocks/wood"] = block;

  var top_height = 15;
  for (var x = 0; x < num_blocks; x++) {
    blocks[x] = new Array(num_blocks);
    var delta = 1;
    top_height += 2 * delta * Math.random() - delta;
    for (var y = 0; y < num_blocks; y++) {
      if (y < top_height) {
        blocks[x][y] = 0;
      } else if (y > top_height + 1) {
        blocks[x][y] = 1;
      } else {
        blocks[x][y] = 2;
      }
    }
  }
}

function ClearScreen() {
  //context.fillStyle = "rgba(200, 200, 200, 1)"
  //context.fillRect(0, 0, canvas.width, canvas.height);
}

function DrawBlocks() {
  for (var x = 0; x < num_blocks; x++) {
    var row = blocks[x];
    for (var y = 0; y < num_blocks; y++) {
      var block = row[y];
      switch (block) {
        case 0:
          img = assets["blocks/sky"];
          break;
        case 1:
          img = assets["blocks/earth"];
          break;
        case 2:
          img = assets["blocks/top"];
          break;
        case 3:
          img = assets["blocks/wood"];
          break;
      }
      context.drawImage(img, block_size * x, block_size * y, block_size, block_size);
    }
  }
}

function DrawGuy() {
  var guy_size = 40;
  context.drawImage(assets["guy"],
      block_size * position[0] - guy_size / 4,
      block_size * position[1] - guy_size / 2,
      guy_size, guy_size);
}

function DoPhysics() {
  var guy_x = position[0];
  var guy_y = position[1];
  if (blocks[guy_x][guy_y] == 0 &&
      blocks[guy_x][guy_y+1] == 0) {
    position[1] += 1;
  }
}

function DrawLegend() {
  var blocks = ["blocks/earth", "blocks/wood"];
  var num_blocks = 2;
  var mid_x = canvas.width/2;
  var border = 2;
  var left = mid_x - blocks.length * (block_size + 2 * border);
  var top = canvas.height - block_size - 2 * border;
  var x = left;
  for (var i = 0; i < 2; i++) {
    var img = assets[blocks[i]];
    context.fillStyle = "rgba(128, 128, 128, 1)"
    context.fillRect(x, top, block_size + 2 * border, block_size + 2 * border);
    context.drawImage(img, x + border, top + border, block_size, block_size);
    x += block_size + 2 * border;
  }
}

function DrawScene() {
  DoPhysics();
  ClearScreen();
  DrawBlocks();
  DrawGuy();
  DrawLegend();
  setTimeout("DrawScene();", 100);
}

function GetBlockAt(pos) {
  return blocks[pos[0]][pos[1]];
}

function SetBlockAt(pos, value) {
  blocks[pos[0]][pos[1]] = value;
  var sound;
  if (value === 0) {
    sound = document.getElementById("remove_block_sound");
  } else {
    sound = document.getElementById("add_block_sound");
  }
  sound.play();
}

function FixColumn(x) {
  var air = true;
  var top = true;
  for (var y = 0; y < num_blocks; y++) {
    var in_air = blocks[x][y] == 0;
    var in_dirt = blocks[x][y] == 1 || blocks[x][y] == 2;
    if (in_dirt && !top) {
      blocks[x][y] = 1;
    }
    if (in_dirt && air && top) {
      blocks[x][y] = 2;
      top = false;
    }
    if (in_air) {
      air = true;
      top = true;
    }
  }
}

function AddBlock(current_pos, add_pos) {
  var add_below = (current_pos[0] == add_pos[0]) &&
      (current_pos[1] == add_pos[1] - 1);
  if (GetBlockAt(add_pos) == 0) {
    SetBlockAt(add_pos, 1);
  } else if (add_below) {
    // add at current spot and move up, if possible
    var above_pos = [current_pos[0], current_pos[1] - 1];
    if (GetBlockAt(above_pos) == 0) {
      SetBlockAt(current_pos, 1);
      position[1] -= 1;
    }
  }
  FixColumn(add_pos[0]);
}

function RemoveBlock(pos) {
  SetBlockAt(pos, 0);
  FixColumn(pos[0]);
}

function handleKeyDown(evt) {
  evt = (evt) ? evt : ((window.event) ? event : null);
  if (evt) {
    switch (evt.keyCode) {
     case 32:  // spacebar
       position[1] -= 3;
       if (position[1] < 0) {
         position[1] = 0;
       }
       break;
    }
  }
}

function handleArrowKeys(evt) {
  evt = (evt) ? evt : ((window.event) ? event : null);
  if (evt) {
    var dir = [0, 0];
    switch (evt.keyCode) {
     case 37:
       dir = [-1, 0];
       break;
     case 38:
       dir = [0, -1];
       break;
     case 39:
       dir = [1, 0];
       break;
     case 40:
       dir = [0, 1];
       break;
    }
    var new_pos = [position[0] + dir[0], position[1] + dir[1]];
    if (evt.altKey) {
      // break
      RemoveBlock(new_pos);
    } else if (evt.shiftKey) {
      // add
      AddBlock(position, new_pos, evt.keyCode == 40);
    } else {
      // move
      var new_pos = [position[0] + dir[0], position[1] + dir[1]];
      if (GetBlockAt(new_pos) == 0) {
        position = new_pos;
      }
    }
  }
}

function getBlockXandY(e) {
  return [
    ((e.clientX - canvas.getBoundingClientRect().left) / block_size) | 0,
    ((e.clientY - canvas.getBoundingClientRect().top) / block_size) | 0
  ]
}

document.onkeydown = handleKeyDown;
document.onkeyup = handleArrowKeys;
canvas.addEventListener("click", function(e) {
  var click_pos = getBlockXandY(e);
  if (e.shiftKey) {
    AddBlock(position, click_pos);
  } else {
    RemoveBlock(click_pos);
  }
}, false);

InitializeWorld();
DrawScene();

</script>
</body>
</html>
